home *** CD-ROM | disk | FTP | other *** search
/ Winzipper / Winzipper_ISO.iso / programming / oracle7 7.2 / DB / UTIL72 / DBMSALRT.SQL < prev    next >
Encoding:
Text File  |  1995-05-09  |  14.2 KB  |  312 lines

  1. rem 
  2. rem $Header: dbmsalrt.sql 7020100.1 94/09/23 22:14:39 cli Generic<base> $ 
  3. rem 
  4. Rem  Copyright (c) 1991 by Oracle Corporation 
  5. Rem    NAME
  6. Rem     dbmsalrt.sql - Blocking implementation of DBMS "alerts"
  7. Rem    DESCRIPTION
  8. Rem     Routines to wait-for, and signal, a named event.  The waiting
  9. Rem     session will block in the database until the event occurs, or until
  10. Rem     a timeout expires.  The implementation avoids polling except when
  11. Rem     running in parallel server mode.
  12. Rem    RETURNS
  13. Rem 
  14. Rem    NOTES
  15. Rem      The procedural option is needed to use this facility.
  16. Rem
  17. Rem    MODIFIED   (MM/DD/YY)
  18. Rem     adowning   03/29/94 -  merge changes from branch 1.7.710.1
  19. Rem     adowning   02/02/94 -  split file into public / private binary files
  20. Rem     mmoore     03/17/93 -  merge changes from branch 1.6.312.1 
  21. Rem     mmoore     03/11/92 - #(153818) fix looping in signal upon cleanup
  22. Rem     rkooi      12/03/92 - #141803, improve some comments 
  23. Rem     rkooi      11/25/92 -  allow signalling and waiting in same session 
  24. Rem     rkooi      11/17/92 -  pipe cleanup bug 
  25. Rem     rkooi      11/12/92 -  don't call removeall from signal
  26. Rem     rkooi      08/12/92 -  surface removeall function 
  27. Rem     rkooi      06/05/92 -  Creation 
  28. REM 
  29.  
  30. create or replace package dbms_alert is
  31.  
  32.   ------------
  33.   --  OVERVIEW
  34.   --
  35.   --  This package provides support for the asynchronous (as opposed to
  36.   --  polling) notification of database events.  By appropriate use of
  37.   --  this package and database triggers, an application can cause itself
  38.   --  to be notified whenever values of interest in the database are
  39.   --  changed.  
  40.   --
  41.   --  For example, suppose a graphics tool is displaying a graph of some
  42.   --  data from a database table.  The graphics tool can, after reading and
  43.   --  graphing the data, wait on a database alert ('dbms_alert.waitone')
  44.   --  covering the data just read.  The tool will automatically wake up when
  45.   --  the data is changed by any other user.  All that is required is that a
  46.   --  trigger be placed on the database table which then performs a signal
  47.   --  ('dbms_alert.signal') whenever the trigger is fired.
  48.   --
  49.   --  Alerts are transaction based.  This means that the waiting session
  50.   --  does not get alerted until the transaction signalling the alert commits.
  51.   --
  52.   --  There can be any number of concurrent signallers of a given alert, and
  53.   --  there can be any number of concurrent waiters on a given alert.
  54.   --
  55.   --  A waiting application will be blocked in the database and cannot do
  56.   --  any other work.
  57.   --  
  58.   --  Most of the calls in the package, except for 'signal', do commits.
  59.   --
  60.  
  61.   -----------
  62.   --  EXAMPLE
  63.   --
  64.   --  Suppose the application wishes to graph average salaries, say by
  65.   --  department, for all employees.  So the application needs to know
  66.   --  whenever 'emp' is changed.  The application would look like this:
  67.   --
  68.   --      dbms_alert.register('emp_table_alert');  
  69.   --    readagain:
  70.   --      <read the emp table and graph it>
  71.   --      dbms_alert.waitone('emp_table_alert', :message, :status);
  72.   --      if status = 0 then goto readagain; else <error condition>
  73.   --
  74.   --  The 'emp' table would have a trigger similar to the following:
  75.   --
  76.   --    create trigger emptrig after insert or update or delete on emp
  77.   --    begin
  78.   --      dbms_alert.signal('emp_table_alert', 'message_text');
  79.   --    end;
  80.   --
  81.   --  When the application is no longer interested in the alert, it does
  82.   --    dbms_alert.remove('emp_table_alert');
  83.   --  This is important since it reduces the amount of work required by
  84.   --  the alert signaller.
  85.   --
  86.   --  If a session exits (or dies) while there exist registered alerts,
  87.   --  they will eventually be cleaned up by future users of this package.
  88.   --
  89.   --  The above example guarantees that the application will always see
  90.   --  the latest data, although it may not see every intermediate value.
  91.  
  92.  
  93.   --------------
  94.   --  VARIATIONS
  95.   --
  96.   --  The application can register for multiple events and can then wait for
  97.   --  any of them to occur using the 'waitany' call.
  98.   --
  99.   --  An application can also supply an optional 'timeout' parameter to the
  100.   --  'waitone' or 'waitany' calls.  A 'timeout' of 0 returns immediately
  101.   --  if there is no pending alert.
  102.   --
  103.   --  The signalling session can optionally pass a message which will be
  104.   --  received by the waiting session.
  105.   --
  106.   --  Alerts may be signalled more often than the corresponding application
  107.   --  'wait' calls.  In such cases the older alerts are discaded.  The 
  108.   --  application always gets the latest alert (based on transaction commit 
  109.   --  times).
  110.   -- 
  111.   --  If the application does not require transaction based alerts, then the 
  112.   --  'dbms_pipe' package may provide a useful alternative
  113.   --
  114.   --  If the transaction is rolled back after the call to 'dbms_alert.signal',
  115.   --  no alert will occur.
  116.   -- 
  117.   --  It is possible to receive an alert, read the data, and find that no
  118.   --  data has changed.  This is because the data changed after the *prior*
  119.   --  alert, but before the data was read for that *prior* alert.
  120.  
  121.  
  122.   --------------------------
  123.   --  IMPLEMENTATION DETAILS
  124.   --
  125.   --  In most cases the implementation is event-driven, i.e., there are no
  126.   --  polling loops.  There are two cases where polling loops can occur:
  127.   --
  128.   --    1) Parallel mode.  If your database is running parallel mode then
  129.   --       a polling loop is required to check for alerts from another
  130.   --       instance.  The polling loop defaults to one second and is settable
  131.   --       by the 'set_defaults' call.
  132.   --    2) Waitany call.  If you use the 'waitany' call, and a signalling 
  133.   --       session does a signal but does not commit within one second of the
  134.   --       signal, then a polling loop is required so that this uncommitted
  135.   --       alert does not camouflage other alerts.  The polling loop begins
  136.   --       at a one second interval and exponentially backs off to 30 second
  137.   --       intervals.
  138.   --  
  139.   --  This package uses the dbms_lock package (for synchronization between
  140.   --  signallers and waiters) and the dbms_pipe package (for asynchronous
  141.   --  event dispatching).
  142.  
  143.   -------------------------------------------------------
  144.   --  INTERACTION WITH MULTI-THREADED AND PARALLEL SERVER
  145.   --
  146.   --  When running with the parallel server AND multi-threaded server, a
  147.   --  multi-threaded (dispatcher) "shared server" will be bound to a
  148.   --  session (and therefore not shareable) during the time a session has
  149.   --  any alerts "registered", OR from the time a session "signals" an
  150.   --  alert until the time the session commits.  Therefore, applications
  151.   --  which register for alerts should use "dedicated servers" rather than
  152.   --  connecting through the dispatcher (to a "shared server") since
  153.   --  registration typically lasts for a long time, and applications which
  154.   --  cause "signals" should have relatively short transactions so as not
  155.   --  to tie up "shared servers" for too long.
  156.  
  157.   ------------
  158.   --  SECURITY
  159.   --
  160.   --  Security on this package may be controlled by granting execute on 
  161.   --  this package to just those users or roles that you trust.  You may
  162.   --  wish to write a cover package on top of this one which restricts
  163.   --  the alertnames used.  Execute privilege on this cover package can
  164.   --  then be granted rather than on this package.    
  165.  
  166.  
  167.   -------------
  168.   --  RESOURCES
  169.   --
  170.   --  This package uses one database pipe and two locks for each alert a 
  171.   --  session has registered.
  172.  
  173.  
  174.   ---------------------
  175.   --  SPECIAL CONSTANTS
  176.   --
  177.   maxwait constant integer :=  86400000; -- 1000 days 
  178.   --  The maximum time to wait for an alert (essentially forever).
  179.  
  180.  
  181.   ----------------------------
  182.   --  PROCEDURES AND FUNCTIONS
  183.   --
  184.   procedure set_defaults(sensitivity in number);
  185.   --  Set various defaults for this package.
  186.   --  Input parameters:
  187.   --    sensitivity
  188.   --      In case a polling loop is required (see "Implementation Details"
  189.   --      above), this is the time to sleep between polls.  Deafult is 5 sec.
  190.   --
  191.   procedure register(name in varchar2);
  192.   --  Register interest in an alert.  A session may register interest in
  193.   --    an unlimited number of alerts.  Alerts should be de-registered when
  194.   --    the session no longer has any interest (see 'remove').  This call
  195.   --    always performs a 'commit'.
  196.   --  Input parameters:
  197.   --    name
  198.   --      The name of the alert in which this session is interested.
  199.   --      WARNING:  Alert names beginning with 'ORA$' are reserved for use for
  200.   --      products provided by Oracle Corporation.  Name must be 30 bytes
  201.   --      or less.  The name is case-insensitive.
  202.   --
  203.   procedure remove(name in varchar2);
  204.   --  Remove alert from registration list.  Do this when the session is no
  205.   --    longer interested in an alert.  Removing an alert is important
  206.   --    since it will reduce the amount of work done by signalers of the alert.
  207.   --    If a session dies without removing the alert, that alert will
  208.   --    eventually (but not immediately) be cleaned up.  This call always
  209.   --    performs a commit.
  210.   --  Input parameters:
  211.   --    name
  212.   --      The name of the alert to be removed from registration list. The
  213.   --      name is case-insensitive.
  214.   --
  215.   procedure removeall;
  216.   --  Remove all alerts for this session from registration list.  Do this 
  217.   --    when the session is no longer interested in any alerts.  Removing 
  218.   --    alerts is important since it will reduce the amount of work done 
  219.   --    by signalers of the alert.  If a session dies without removing all
  220.   --    of its alerts, the alerts will eventually (but not immediately)
  221.   --    be cleaned up.  This call always performs a commit.
  222.   --
  223.   --    This procedure is called automatically upon first reference to this
  224.   --    package during a session.  Therefore no alerts from prior sessions
  225.   --    which may have terminated abnormally can affect this session.
  226.   procedure waitany(name out varchar2, 
  227.                     message out varchar2, 
  228.                     status out integer,
  229.                     timeout in number default maxwait);
  230.   --  Wait for an alert to occur for any of the alerts for which this
  231.   --    session is registered.  Although probably unusual, the same session
  232.   --    that waits for the alert may also first signal the alert.  In this
  233.   --    case remember to commit after the signal and prior to the wait.  
  234.   --    Otherwise a lock request exception (status 4) will occur.  This
  235.   --    call always performs a commit.
  236.   --  Input parameters:
  237.   --    timeout
  238.   --      The maximum time to wait for an alert.  If no alert occurs before
  239.   --      timeout seconds, then this call will return with status of 1.
  240.   --  Output parameters:
  241.   --    name
  242.   --      The name of the alert that occurred, in uppercase.
  243.   --    message
  244.   --      The message associated with the alert.  This is the message
  245.   --      provided by the 'signal' call.  Note that if multiple signals
  246.   --      on this alert occurred before the waitany call, then the message
  247.   --      will correspond to the most recent signal call.  Messages from
  248.   --      prior signal calls will be discarded.
  249.   --    status
  250.   --      0 - alert occurred
  251.   --      1 - timeout occurred
  252.   --  Errors raised:
  253.   --    -20000, ORU-10024: there are no alerts registered.
  254.   --       Cause: You must register an alert before waiting.
  255.   --
  256.   procedure waitone(name in varchar2, 
  257.                     message out varchar2, 
  258.                     status out integer,
  259.                     timeout in number default maxwait);
  260.   --  Wait for specified alert to occur. If the alert was signalled since
  261.   --    the register or last waitone/waitany, then this call will return
  262.   --    immediately.  The same session that waits for the alert may also
  263.   --    first signal the alert.  In this case remember to commit after the
  264.   --    signal and prior to the wait.  Otherwise a lock request exception
  265.   --    (status 4) will occur.  This call always performs a commit.
  266.   --  Input parameters:
  267.   --    name
  268.   --      The name of the alert to wait for. The name is case-insensitive.
  269.   --    timeout
  270.   --      The maximum time to wait for this alert.  If no alert occurs before
  271.   --      timeout seconds, then this call will return with status of 1.
  272.   --      If the named alert has not been registered then the this call
  273.   --      will return after the timeout period expires.
  274.   --  Output parameters:
  275.   --    message
  276.   --      The message associated with the alert.  This is the message
  277.   --      provided by the 'signal' call.  Note that if multiple signals
  278.   --      on this alert occurred before the waitone call, then the message
  279.   --      will correspond to the most recent signal call.  Messages from
  280.   --      prior signal calls will be discarded.  The message may be up to
  281.   --      1800 bytes.
  282.   --    status
  283.   --      0 - alert occurred
  284.   --      1 - timeout occurred
  285.   --
  286.   procedure signal(name in varchar2, 
  287.                    message in varchar2);
  288.   --  Signal an alert.
  289.   --  Input parameters:
  290.   --    name
  291.   --      Name of the alert to signal.  The effect of the signal call only
  292.   --      occurs when the transaction in which it is made commits.  If the
  293.   --      transaction rolls back, then the effect of the signal call is as
  294.   --      if it had never occurred.  All sessions that have registered
  295.   --      interest in this alert will be notified.  If the interested sessions
  296.   --      are currently waiting, they will be awakened.  If the interested
  297.   --      sessions are not currently waiting, then they will be notified the
  298.   --      next time they do a wait call.  Multiple sessions may concurrently
  299.   --      perform signals on the same alert.  However the first session
  300.   --      will block concurrent sessions until the first session commits.
  301.   --      Name must be 30 bytes or less. It is case-insensitive.  This call
  302.   --      does not perform a commit.
  303.   --    message
  304.   --      Message to associate with this alert.  This will be passed to
  305.   --      the waiting session.  The waiting session may be able to avoid
  306.   --      reading the database after the alert occurs by using the
  307.   --      information in this message.  The message must be 1800 bytes or less.
  308.  
  309. end;
  310. /
  311.  
  312.